/* Copyright (c) 2001 IBK-Landquart-Switzerland. All rights reserved.
 *
 * Module      :  ZCsl.hpp
 * Application :  CSL kernel
 * Purpose     :  Native class interface
 *
 * Date        Description                                 Who
 * -------------------------------------------------------------------------------------------
 * 2013.01.05  First implementation                        J-L.Amitousa-Mankoy, B.de Finance  
 *
 * OPEN SOURCE LICENSE
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to IBK at info@ibk-software.ch.
 */

#define ZC_BUILDING_ZCSL

#include <ZCsl.hpp>
#include <cstring>
#include <cstdlib>

ZCsl::SavedContinuations::SavedContinuations(ZCsl* aParent): iParent(aParent){}
ZCsl::SavedContinuations::~SavedContinuations(){}

void ZCsl::SavedContinuations::restaureContinuation(
		ZString aName,
		ZException** pAExcpt, 
	    PackedInstruction** pALoAddr, 
	    PackedInstruction** pAHiAddr,
		PackedInstruction** pAINext, 
		ZString* pAV2, 
		Variable** pAV,
		double* pAD2, 
		long* pAI2,
		ZBoolean* pAHead,
		Function** pAAFunc)
		{
   for (std::list<SavedContinuation>::iterator it=listContinuations.begin(); it != listContinuations.end(); ++it){
     ZString iName = *(it->contName);
     if (aName==iName){/*compare the name*/
           it->restaure(
			pAExcpt, pALoAddr, pAHiAddr, pAINext, 
				pAV2, pAV, pAD2, pAI2, pAHead, pAAFunc);
	   break;
        }
   }
}

void ZCsl::SavedContinuations::saveContinuation(
										ZString aName, 
										ZException* excpt, 
										PackedInstruction* loAddr, 
										PackedInstruction* hiAddr,
										PackedInstruction* iNext, 
										ZString v2,
										Variable* v,
										double d2,
										long i2, 
										ZBoolean head,
										Function* aFunc){ 

  ZBoolean found = ZBoolean(zFalse);

  for (std::list<SavedContinuation>::iterator it=listContinuations.begin(); it != listContinuations.end(); ++it){
    ZString iName = *(it->contName);
    if (aName==iName){/*compare the name*/
      found = ZBoolean(zTrue);
    }
  }
  
  if(found == zFalse){
    ZString* iName = new ZString(aName);
    listContinuations.push_front(
				 SavedContinuation(iParent, iName, excpt, loAddr, 
						   hiAddr, iNext, v2, v, d2, i2, head, 
						   aFunc));
  }
}

ZCsl::Variable* ZCsl::SavedContinuation::copyListVar(Variable* original){
    int isInit = 0;
    Variable* copyVar = NULL;
    Variable* tmp = original;
    Variable* tmp2 = NULL;
    Variable* tmp3 = NULL;
    while(tmp != NULL){

        tmp2 = new Variable(
   tmp->iParent, NULL, NULL, NULL, NULL, NULL, NULL, NULL);

        memcpy(tmp2, tmp, sizeof(Variable)); 

        if(!isInit){
            copyVar = tmp2;
            isInit = 1;
        }
        tmp = tmp->iPrev;
        if(tmp3 != NULL){
            tmp3->iPrev = tmp2;
        }
        tmp3 = tmp2;
    }
    return copyVar;
}


ZCsl::Block* ZCsl::SavedContinuation::copyListBlock(Block* original){
    int isInit = 0;
    Block* copyBlock = NULL;
    Block* tmp = original;
    Block* tmp2 = NULL;
    Block* tmp3 = NULL;
    while(tmp != NULL){
        tmp2 = new Block(tmp->iParent, NULL, NULL);
        
        memcpy(tmp2, tmp, sizeof(Block));
        //vars' copy 
        tmp2->iVars = copyListVar(tmp->iVars);

        if(!isInit){
            copyBlock = tmp2;
            isInit = 1;
        }
        tmp = tmp->iPrev;
        if(tmp3 != NULL){
            tmp3->iPrev = tmp2;
        }
        tmp3 = tmp2;
    }
    return copyBlock;
}

ZCsl::Function* ZCsl::SavedContinuation::copyListFunct(Function* original){
    int isInit = 0;
    Function* copyFunct = NULL;
    Function* tmp = original;
    Function* tmp2 = NULL;
    Function* tmp3 = NULL;
    while(tmp != NULL){
        tmp2 = new Function(tmp->iParent, NULL, NULL);
        memcpy(tmp2, tmp, sizeof(Function));
        if(!isInit){
            copyFunct = tmp2;
            isInit = 1;
        }
        tmp = tmp->iPrev;
        if(tmp3 != NULL){
            tmp3->iPrev = tmp2;
        }
        tmp3 = tmp2;
    }
    return copyFunct;
}

ZCsl::SavedContinuation::SavedContinuation(ZCsl* aParent,
										   ZString* aName,          
										   ZException* aExcpt, 
										   PackedInstruction* aLoAddr, 
										   PackedInstruction* aHiAddr,
										   PackedInstruction* aINext, 
										   ZString aV2, 
										   Variable* aV,
										   double aD2, 
										   long aI2,
										   ZBoolean aHead,
										   Function* aAFunc
										   ): 
                                           iParent(aParent),
                                           contName(aName),
										   excpt(aExcpt),
										   loAddr(aLoAddr),
										   hiAddr(aHiAddr),
										   iNext(aINext),
										   v2(aV2),
										   v(aV),
										   d2(aD2),
										   i2(aI2),
										   head(aHead),
										   aFunc(aAFunc)
										   {

                        
             //copy the stack
             stackSize = iParent->iStackSize;
             savedStack = new ZString[stackSize];
             memcpy(savedStack, iParent->iStack, sizeof(ZString)*(stackSize));
          
             //copy the blocks iBlock
             savedBlock = copyListBlock(iParent->iBlock);
             

             //copy the blocks iStats
             savedStats = copyListBlock(iParent->iStats);
         

             //copy the functions calls same thing to do   
             savedCalls = copyListFunct(iParent->iCalls);

             //sauvegarde du tos
             savedTos = savedStack + (iParent->iTos - iParent->iStack);

             savedFlags = iParent->iFlags;

             saveStat =savedStats + (iParent->iStat - iParent->iStats);             
             saveList = iParent->iList;              
             saveInDirective = iParent->iInDirective;       
             saveInput = iParent->iInput;             
             saveSym = iParent->iSym;               
             saveIdent = iParent->iIdent;             
             saveValue = iParent->iValue;             
             saveCurrFunc =savedCalls + (iParent->iCurrFunc - iParent->iCalls);    
}

ZCsl::SavedContinuation::~SavedContinuation(){}


void ZCsl::SavedContinuation::restaure(
		ZException** pAExcpt, 
	    PackedInstruction** pALoAddr, 
	    PackedInstruction** pAHiAddr,
		PackedInstruction** pAINext, 
		ZString* pAV2, 
		Variable** pAV,
		double* pAD2, 
		long* pAI2,
		ZBoolean* pAHead,
		Function** pAAFunc)
{

				*pAExcpt  = excpt;
				*pALoAddr = loAddr;
				*pAHiAddr = hiAddr;
				*pAINext = iNext;
				*pAV2 = v2;
				*pAD2 = d2;
				*pAI2 = i2;
				*pAHead = head;
				*pAAFunc = aFunc;
				

    //i suppose that we should restaure with a copy of our continuation because 
    //we don't want it to be modified by side effect.

             //copy the stack
             iParent->iStackSize = stackSize;
             iParent->iStack = new ZString[stackSize];
             memcpy(iParent->iStack, savedStack, sizeof(ZString)*(stackSize));

             //copy the blocks savedBlock
             iParent->iBlock = copyListBlock(savedBlock);
             

             //copy the blocks iStats
             iParent->iStats = copyListBlock(savedStats);
         

             //copy the functions calls same thing to do   
             iParent->iCalls = copyListFunct(savedCalls);

             //sauvegarde du tos
             iParent->iTos =  iParent->iStack + (savedTos - savedStack);

             iParent->iFlags = savedFlags; 
             iParent->iStat = iParent->iStats + (saveStat - savedStats);   
             iParent->iList = saveList;   
             iParent->iInDirective = saveInDirective;
             iParent->iInput = saveInput;                 
             iParent->iSym = saveSym;                
             iParent->iIdent = saveIdent;
             iParent->iValue = saveValue;          
             iParent->iCurrFunc = iParent->iCalls +  (saveCurrFunc - savedCalls);      
}
